package com.zwan.oam_rtc.imps;

import com.zwan.oam_rtc.bean.JimpSettings;
import com.zwan.oam_rtc.utils.messages.MessageHead;
import com.zwan.oam_rtc.utils.messages.MsgStruct;
import com.zwan.oam_rtc.utils.messages.PID;
import com.zwan.oam_rtc.utils.wintcp.ByteTransfer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.text.MessageFormat;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Service
@Slf4j
public class JavaImp implements IService{
	
	
	private JimpSettings jimpSettings;
	

	private static JavaImp _instance = new JavaImp();
	private ExecutorService executor = Executors.newCachedThreadPool();
	private boolean isRunning = false;
	/**
	 * Handler 实例列表, 根据pno查找 业务逻辑模块
	 */
	//ConcurrentHashMap默认情况下支持16个线程并发写入，超过16个时，可能有一些线程需要等待，可通过
	//设置currencyLevel构造参数（默认16）来支持更多线程并发。
	private Map<Integer, PnoHandler> handlers = new ConcurrentHashMap<Integer, PnoHandler>();
	
	/**
	 * 做为服务端时的客户端连接列表，根据module查找
	 */
	private Map<Integer, ServerHandler> serverHandlers = new ConcurrentHashMap<Integer, ServerHandler>();
	/**
	 * 做为客户端时的客户端连接列表
	 */	
	private Map<Integer, ClientHandler> clientHandlers = new ConcurrentHashMap<Integer, ClientHandler>();
	/**
	 * 服务端Socket
	 */
	private ServerSocket serverSocket = null;
	private int moduleno = 0;
	private short unit = 0;
	private short office = 0;
	private ByteOrder byteOrder = ByteOrder.BIG_ENDIAN;

	public JavaImp(){
		if (_instance != null)
			_instance.shutdown();
		_instance = this;
		ByteTransfer.CHARSET = "UTF-8";
	}

	public static JavaImp getInstance(){
		return _instance;
	}

	public void setExecutors(ExecutorService executor){
		this.executor = executor;
	}

	public ExecutorService getExecutor(){
		return this.executor;
	}

	public void stop(){
		if (!isRunning) return;
		// 不再接受新任务
		executor.shutdownNow();//关闭线程池
		// 停止处理
		for (Iterator<PnoHandler> iter = handlers.values().iterator(); iter.hasNext();) {
			PnoHandler handler = iter.next();
			handler.destroy();
		}
		handlers.clear();
		// 关闭服务端Socket
		if (serverSocket != null && serverSocket.isBound())
		{
			try {
				serverSocket.close();
				serverSocket = null;
			} catch (IOException e) {
				log.info(e.toString());
			}
		}
		// 关闭客户端Socket
		for (Iterator<ServerHandler> iter = serverHandlers.values().iterator(); iter.hasNext();) {
			ServerHandler handler = iter.next();
			handler.close();
		}
		serverHandlers.clear();
		for (Iterator<ClientHandler> iterator = clientHandlers.values().iterator(); iterator.hasNext();) {
			ClientHandler handler = iterator.next();
			handler.close();
		}
		clientHandlers.clear();

	}

	public int getModuleNo(){
		return moduleno;
	}
	public ByteOrder getByteOrder(){
		return byteOrder;
	}

	public PID getPID(int pno){
		return new PID(pno, unit, (short)moduleno, office);
	}

	public Map<Integer, ServerHandler> getServerHandlers(){
		return this.serverHandlers;
	}

	public Map<Integer, ClientHandler> getClientHandlers(){
		return this.clientHandlers;
	}

	public ServerHandler getServerHandler(int moduleno){
		return this.serverHandlers.get(moduleno);
	}

	public ClientHandler getClientHandler(int moduleno){
		return this.clientHandlers.get(moduleno);
	}

	/**
	 * 根据pno从配置中获得处理类实例
	 * @param pno
	 * @return
	 */

	public PnoHandler getHandler(int pno){
		return this.handlers.get(pno);
	}

	public PnoHandler getHandlerInstance(Class<?> cls){
		for (Iterator<PnoHandler> iterator = handlers.values().iterator(); iterator.hasNext();) {
			PnoHandler h = iterator.next();
			if (h.getClass().equals(cls)) {
				return h;
			}
		}
		return null;
	}

	public ByteOrder getByteOrder(int moduleno){
		ClientHandler ch = this.getClientHandler(moduleno);
		if (ch != null){
			return ch.getByteOrder();
		}
		else
			return this.byteOrder;
	}

	/**
	 * 
	 * @param head
	 * @param body
	 */
	public void sendMessage(MessageHead head, byte[] body){
		head.setBodyLen(body.length);
		int descmodule = head.getReceiver().getModule();
		if (descmodule == moduleno) //
		{
			if (!head.isCheckMessage() && head.getReceiver().getPno() != 0)
				executor.submit(new HandlerRunner(head, ByteBuffer.wrap(body), byteOrder));
			return;
		}
		ServerHandler sh = this.serverHandlers.get(descmodule);
		if (sh != null){
			sh.sendMessage(head, body);
			return;
		}
		ClientHandler ch = this.clientHandlers.get(descmodule);
		if (ch != null){
			ch.sendMessage(head, body);
		}
		else
		{
			log.info(MessageFormat.format("Send message error, cannot found module: {0}", descmodule));
		}
	}

	/**
	 * javaImp中的发送消息方法，该方法将参数包装成MessageHead和body，调用JavaImpl中
	 * sendMessaage（head，body）发送
	 * @param srcpno 源程序的程序号（这个消息来自那个程序）
	 * @param descmodule 目的程序的module？
	 * @param descpno  目标程序的程序号（这个消息是发给目标哪个程序的）
	 * @param eventid  需要响应此消息的事件的业务号
	 * @param body    封装成目标能够接收的消息模式（SLPAccessMessage）后再转换成的字符串 
	 */
	public void sendMessage(int srcpno, int descmodule, int descpno, int eventid, byte[] body){
		MessageHead head = new MessageHead();
			 
		head.getSender().setModule((short)JavaImp.getInstance().getJimpSettings().getWintcp().getModule().intValue());
		head.getSender().setPno(srcpno);
		head.getSender().setUnit(unit);
		head.getSender().setPostoffice((short)JavaImp.getInstance().getJimpSettings().getWintcp().getPostoffice().intValue());		
		head.getReceiver().setModule((short)descmodule);
		head.getReceiver().setPno(descpno);
		head.getReceiver().setUnit(unit);
		head.getReceiver().setPostoffice((short)JavaImp.getInstance().getJimpSettings().getWintcp().getPostoffice().intValue());
		head.setBodyLen(body.length);
		head.setSecretfield(head.calcSecretField());
		head.setEventid(eventid);
		sendMessage(head, body);
	}
	/**
	 * javaImp中的发送消息方法，该方法将参数包装成MessageHead和body，调用JavaImpl中
	 * sendMessaage（head，body）发送
	 * @param sender PID消息来自哪里
	 * @param receiver PID消息目的地
	 * @param eventid 触发业务的事件号（应该是触发SCP端业务事件的号码）
	 * @param body  封装成目标能够接收的消息模式（SLPAccessMessage）后再转换成的字符串 
	 */
	public void sendMessage(PID sender, PID receiver, int eventid, byte[] body){
		MessageHead head = new MessageHead();
		head.setSender(sender);
		head.setReceiver(receiver);
		head.setEventid(eventid);
		head.setBodyLen(body.length);
		head.setSecretfield(head.calcSecretField());
		sendMessage(head, body);
	}

	public void sendMessage(int srcpno, int descmodule, int descpno, int eventid, MsgStruct msg){
		sendMessage(srcpno, descmodule, descpno, eventid, msg);
	}

	@Override
	public void finalize() throws Throwable {
		log.info("Shutdown Javaimp......");
		stop();
		super.finalize();
	}


	public void addHandler(int slpPno, PnoHandler handler) {
		this.handlers.put(slpPno, handler);
	}

	public Map<Integer, PnoHandler> getHandlers() {
		return this.handlers;
	}

	@Override
	public boolean init(String serviceName, JimpSettings js) throws Exception {
		stop();
		//		try {
		handlers.clear();
		
		// load Handlers
		setJimpSettings(js);
		try {
			//this.jimpSettings.getHandler().getClazz() = 配置文件中的com.zwan.zwgw.imps.UserStatusHandler
			Class<?> cls = Class.forName(this.jimpSettings.getHandler().getClazz());
			if (cls != null){
				PnoHandler handler = (PnoHandler)cls.getDeclaredConstructor().newInstance();//UserStatusHandler
				handler.init(this.jimpSettings.getHandler().getPno());//对应的程序号放入handler中
				this.handlers.put(this.jimpSettings.getHandler().getPno(), handler);//程序号，对应的handler放进map
				log.info(MessageFormat.format("Handler [{0}] loaded, pno: {1}", this.jimpSettings.getHandler().getClazz(), this.jimpSettings.getHandler().getPno()));
			} else
			{
				log.info(MessageFormat.format("Class [{0}] not found, pno: {1}", this.jimpSettings.getHandler().getClazz(), this.jimpSettings.getHandler().getPno() ));
			}
		} catch (ClassNotFoundException e) {
			log.info(MessageFormat.format("Class [{0}] not found, pno: {1}", this.jimpSettings.getHandler().getClazz(), this.jimpSettings.getHandler().getPno() ));
		} catch (InstantiationException e) {
			log.info("Create handler instance failed");
		} catch (IllegalAccessException e) {
			log.info("Access exception");
		} catch(Exception e){
			log.info("Create handler instance failed");
		}

		// 基本配置
//		moduleno = Integer.parseInt(root.attributeValue("module", "0"));
//		unit = Short.parseShort(root.attributeValue("unit", "0"));
//		office = Short.parseShort(root.attributeValue("office", "0"));
		if (this.jimpSettings.getWintcp().getByteOrder() != null)  //0
			byteOrder = this.jimpSettings.getWintcp().getByteOrder()==1 ? 
					ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN;
		else
			byteOrder = ByteOrder.nativeOrder();

		// 服务端Socket
		//Element serverEle = root.element("Server");
		//executor.submit(new ServerSocketHandler(serverEle));

		// 客户端配置
		ClientHandler ch = new ClientHandler();
		ch.init(); //客户端ch的peerip，peerport等赋值   
		clientHandlers.put(ch.getPeerModule(), ch);  //客户端的handler存入map
		executor.submit(ch); //启动客户端线程

		isRunning = true;
		return isRunning;
	}

	@Override
	public void shutdown() {
		stop();
	}

	@Override
	public synchronized void run() {
		if (isRunning) return;
		if (executor == null){
			executor = Executors.newCachedThreadPool();
		}
	}

	public JimpSettings getJimpSettings() {
		return jimpSettings;
	}

	public void setJimpSettings(JimpSettings jimpSettings) {
		this.jimpSettings = jimpSettings;
	}

}
